/*
*************************************
* PocketGTT
*************************************
This file is part of PocketGTT.

PocketGTT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

PocketGTT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with PocketGTT.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "localdebug.h"
#include "gtt_stopmanager.h"
#include <QUrl>
#include <iostream>
#include <QDebug>
#include <QStringList>
#include <QList>
#include <QCoreApplication>
#include <QInputDialog>
#include <QIntValidator>
#include <QMessageBox>
#include "gtt_line.h"

//#ifndef ATTIVADEBUG
//#define ATTIVADEBUG 1
//#endif

using namespace std;


GTT_StopManager::GTT_StopManager(QDeclarativeContext *ctx, QObject *parent) : QObject(parent), hiddenCtx(ctx)
{
    ////////////////////////////////////////////////////////////
    // connections management
    ////////////////////////////////////////////////////////////

    // after new user request start page download
    connect(this, SIGNAL(GTTon_new_stop_changed(QString)),this, SLOT(GTT_download_info(QString)));

    // start page parsing after download complete from GTT website
    connect(&mywebpage, SIGNAL(loadFinished(bool)),this, SLOT(GTT_parse_info(bool)));

    // start page parsing after download complete from Google Maps
    connect(&gmwebpage, SIGNAL(loadFinished(bool)),this, SLOT(GMaps_parse_info(bool)));

    // update preferred list when the StopInfo is changed
    connect(this, SIGNAL(GTTon_StopInfo_changed()),this, SLOT(preferredStopListUpdate()));




    ////////////////////////////////////////////////////////////
    // start first loading
    ////////////////////////////////////////////////////////////
#if ATTIVADEBUG
    qDebug() << "costruttore" ;
#endif

    setMgsBannerStatus(mgsHidden);
    setStopPageGUIStatus(searchPage);
    setSelectMultipleStopsStatus(SelectMultipleStopsHidden);

    // set up variable and connection for Fermata class
    hiddenStopInfo  = new GTT_Stop(this);

    // connect both update signals of StopInfo & Fermata
    connect(this, SIGNAL(GTTon_StopInfo_changed()), hiddenStopInfo, SIGNAL(GTTon_fermata_updated()));

    // manage preferred stop list
    myPrefStopList = new GTT_PreferredStopList(hiddenCtx);

    // emit signal in order to start download with the first stop in the preferred list
    //    emit GTTon_new_stop_changed(myPrefStopList->getFirstPreferred());
}

void GTT_StopManager::GTT_user_new_stop_def(const QString &stop)
{

#if ATTIVADEBUG
    qDebug() << "call to: GTT_user_new_stop_def(" << stop << ")";
    // qDebug() << "User requested stop: " << stop;
    // qDebug() << "Already loaded stop: " << hiddenStopInfo->getFermataNumero();
#endif


    // stop is for sure int, validation from QML
    // check to avoid reload of same stop
    //    if (stop != hiddenStopInfo->getFermataNumero()) {
    // clean Fermata instance if already filled
    if (!hiddenStopInfo->isEmpty()) {
        hiddenStopInfo->SvuotaFermata();
    }

    // start loading and parsing new stop
    emit GTTon_new_stop_changed(stop);

    //    }

}

////////////////////////////////////////////////////////////
// GTT website page downloading, parsing and saving
////////////////////////////////////////////////////////////
void GTT_StopManager::GTT_download_info(const QString &stop)
{
    // check if stop is already loaded should already be
    // done before emitting "GTTon_new_stop_changed" signal

    // check if some information are already available from QSettings
    // TO BE DONE!!!

    // inform QML that loading has started
    setMgsBannerStatus(msgLoading);

    //download page from GTT website
    //    QString sUrl = "http://www.5t.torino.it/pda/it/arrivi.jsp?n=";
    QString sUrl = "http://m.gtt.to.it/m/it/arrivi.jsp?n=";
    //    mywebpage.mainFrame()->
    mywebpage.mainFrame()->load(QUrl(sUrl.append(stop)));
}

void GTT_StopManager::GTT_parse_info(bool ok)
{
    // check if page download was succesfull
    if (ok) {

        // extract main frame, and store it as a string
        html_doc = mywebpage.mainFrame()->documentElement();
        QString web_page_plain_text = html_doc.toPlainText();
#if ATTIVADEBUG
        qDebug() << web_page_plain_text;
#endif

        if (web_page_plain_text.contains("Attenzione: fermata non trovata!", Qt::CaseInsensitive)) {
            setMgsBannerStatus(errorNonExistingStop);
        }
        else if (web_page_plain_text.contains("Fermata richiesta:", Qt::CaseInsensitive)) {

            QString web_page_plain_text_first_p = html_doc.findFirst("p").toPlainText();
            // look for stop name, number and street and save them
            this->GTT_save_stop_general(web_page_plain_text_first_p);

            // check if position is already known and look for it if not
            if (!hiddenStopInfo->isPositionKnown()) {
                this->GMaps_download_info(hiddenStopInfo->getFermataNumero(), hiddenStopInfo->getFermataNome());
            }

            // check if no passages are planned in the 2h
            //            qDebug() << "ora ora ora" << web_page_plain_text;
            //            qDebug() << html_doc.toPlainText();  //.findFirst("ul.passaggi").toPlainText();
            if (html_doc.findFirst("ul.passaggi").toPlainText().contains("Nessun passaggio", Qt::CaseInsensitive)) {
#if ATTIVADEBUG
                qDebug() << "entrato in no passages +";
#endif
                // set Empty variable in StopInfo
                hiddenStopInfo->LoadComplete();
                emit GTTon_StopInfo_changed();
                setMgsBannerStatus(mgsNoPassagesIn2h);
            }
            else {
#if ATTIVADEBUG
                qDebug() << "entrato in no passages -";
                qDebug() << web_page_plain_text;
#endif

                // parse lines timesheet and save it in memory
                GTT_parse_lines_schedule_info();

                // set Empty variable in StopInfo
                hiddenStopInfo->LoadComplete();

                emit GTTon_StopInfo_changed();
                setStopPageGUIStatus(resultsPage);
                setMgsBannerStatus(mgsHidden);
            }


        }
        else if (web_page_plain_text.contains("Fermate trovate:", Qt::CaseInsensitive)) {
            this->GTT_parseMultipleStops();
        }
        else {
            setMgsBannerStatus(errorUnkownResponse);
        }
        // flush memory
        html_doc.removeAllChildren();

    }
    else {


        // show error banner
        setMgsBannerStatus(errorDownloadingPage);
    }

#if ATTIVADEBUG
        hiddenStopInfo->printLinee();
#endif

}

void GTT_StopManager::GTT_parse_lines_schedule_info() {

    // create variabile for upcoming parsing cicle
    QString text;

    // look for all lines passing by this stop
    // show here example of GTT page
    QWebElementCollection linee = html_doc.findAll("ul.passaggi li");

    // go step by step through the collection
    foreach (QWebElement linea, linee) {
        // new Linea instance
        GTT_Line *localLinea = new GTT_Line(this);
        // use previoudly create variable to store the extraced info as plain text
        text = linea.findFirst("h3").toPlainText();
        // save number of actual line
        localLinea->setLineaNumero(text.split("inea").at(1).trimmed());

        // go through all next scheduled passages of this line
        QWebElementCollection linea_num_stop_time = linea.findAll("span.n");
        foreach (QWebElement stop_lista, linea_num_stop_time) {
            // reuse previously created variable to store the extracted info as plain text
            text = stop_lista.toPlainText();
            // check if Orario is realtime
            // examples: "14:51 *" is realtime while "15:26" is from timesheet
            if (text.contains("*", Qt::CaseInsensitive)) {
                localLinea->addOrario(text.split("*").at(0).trimmed(), true);
            }
            else {
                localLinea->addOrario(text.trimmed());
            }
        }

        hiddenStopInfo->addLinea(localLinea);
    }


}

void GTT_StopManager::GTT_save_stop_general(QString &info) {
    // example of downloaded information from website
    // Name: "Fermata richiesta: 291 - RISORGIMENTO
    // in strada Torino n.23 Beinasco"

    // using qString to extract data
    QStringList list1 = info.split("\n");
    QStringList list2 = list1.at(0).split(": ").at(1).split("-");


    // saving informations
    hiddenStopInfo->setFermataNumero(list2.at(0).trimmed());
    hiddenStopInfo->setFermataNome(list2.at(1).trimmed());
    hiddenStopInfo->setFermataIndirizzo(list1.at(1).trimmed());


#if ATTIVADEBUG
    qDebug() << hiddenStopInfo->getFermataNumero();
    qDebug() << hiddenStopInfo->getFermataNome();
    qDebug() << hiddenStopInfo->getFermataIndirizzo();
#endif

}

void GTT_StopManager::GTT_parseMultipleStops() {

    // downloaded page example

    //    <ul class="passaggi">
    //    <li><a href="arrivi.jsp?n=453"><span class="def">Fermata : </span>453 - RISORGIMENTO<br />
    //                <span class="def">Linee:
    //                13</span>
    //        </a></li>
    //    <li><a href="arrivi.jsp?n=452"><span class="def">Fermata : </span>452 - RISORGIMENTO<br />
    //                <span class="def">Linee:
    //                13</span>
    //        </a></li>
    //    <li><a href="arrivi.jsp?n=291"><span class="def">Fermata : </span>291 - RISORGIMENTO<br />
    //                <span class="def">Linee:
    //                5, 48, 1510, 1511, 1514, 1515</span>
    //        </a></li>
    //    <li><a href="arrivi.jsp?n=290"><span class="def">Fermata : </span>290 - RISORGIMENTO<br />
    //                <span class="def">Linee:
    //                5, 48, 1510, 1511, 1514, 1515</span>
    //        </a></li>
    //    <li><a href="arrivi.jsp?n=2958"><span class="def">Fermata : </span>2958 - RISORGIMENTO EST<br />
    //                <span class="def">Linee:
    //                43, 48</span>
    //        </a></li>
    //    <li><a href="arrivi.jsp?n=2959"><span class="def">Fermata : </span>2959 - RISORGIMENTO EST<br />
    //                <span class="def">Linee:
    //                43, 48</span>
    //        </a></li>
    //    </ul>

    // extract the list from html
    QWebElementCollection stopList = html_doc.findAll("ul.passaggi li");
    //prepare the string list with the options
    //    QStringList mySList;
    hiddenMultiSelectionStop.clear();
    foreach (QWebElement nowStop, stopList) {
        hiddenMultiSelectionStop.append(nowStop.toPlainText().trimmed());
    }

    // inform QML that the list has been updated
    emit GTTon_MultiSelectionStop_changed();

    //    qDebug() << hiddenMultiSelectionStop.isEmpty();
    //    qDebug() << hiddenMultiSelectionStop;

    // prepare input dialog for user selection
    if (!hiddenMultiSelectionStop.isEmpty()) {
        //hide message banner in graphic
        setMgsBannerStatus(mgsHidden);

        // show QML selecation page
        this->setSelectMultipleStopsStatus(SelectMultipleStopsVisible);
        /* QUI FAI FAI FAI */

    }
    else {
        setMgsBannerStatus(errorNonExistingStop);
    }

}


void GTT_StopManager::selectedMultipleStops(int index) {
    //
    //    qDebug() << "mamoe help";
    //    qDebug() << index;
    if (index != -1) {

#if ATTIVADEBUG
        qDebug() << hiddenMultiSelectionStop.at(index);
        qDebug() << hiddenMultiSelectionStop.at(index).split("Fermata :").at(1).split(" - ").at(0).trimmed();
#endif
        QString extractNumber = hiddenMultiSelectionStop.at(index).split("Fermata :").at(1).split(" - ").at(0).trimmed();
        //        qDebug() << extractNumber;
        this->searchByString(extractNumber);

    }
    else {
        // error...do something :)
    }

}

////////////////////////////////////////////////////////////
// Google Maps website page downloading, parsing and saving
////////////////////////////////////////////////////////////
void GTT_StopManager::GMaps_download_info(const QString &stop_num, const QString &stop_name) {

    //download page from google website, set up http link
    //    QString sUrl = "http://maps.googleapis.com/maps/api/geocode/xml?address=Fermata+";
    //    sUrl.append(stop_num);
    //    sUrl.append("+");
    QString sUrl = "http://www.5t.torino.it/5t/trasporto/StopPointCtrl.js.jsp?category=StopPoint&action=search&shortName=";

    sUrl.append(stop_num);
    //    sUrl.append(",+Torino,+Italia&sensor=false");


#if ATTIVADEBUG
    qDebug() << "GMaps download url:";
    qDebug() << sUrl;
#endif

    // start loading page
    gmwebpage.mainFrame()->load(QUrl(sUrl));

}

void GTT_StopManager::GMaps_parse_info(bool ok) {

    // check if page download was succesfull
    if (ok) {

#if ATTIVADEBUG
        qDebug() << "GMaps_parse_info: download Gmaps returned ok";
#endif

        // manages to save Xml into QString
        QString mytext = gmwebpage.mainFrame()->toHtml();

#if ATTIVADEBUG
        qDebug() << mytext;
#endif

        // check result is returned
        if (mytext.contains("shortName")) {

            // manage string to save position coordinate
            hiddenStopInfo->setFermataLat( mytext.split("lat").at(1).split(":").at(1).split(",").at(0).trimmed().toDouble() );
            hiddenStopInfo->setFermataLng( mytext.split("lng").at(1).split(":").at(1).split("\n").at(0).trimmed().toDouble() );
            hiddenStopInfo->setPositionKnown(true);

#if ATTIVADEBUG
            qDebug() << "Print Stop position:";
            qDebug() << hiddenStopInfo->getFermataLat();
            qDebug() << hiddenStopInfo->getFermataLng();
#endif

        }
        else {
#if ATTIVADEBUG
            qDebug() << "Error: GMaps returned multiple results";
            qDebug() << "Setting to default location: piazza castello";
#endif
            hiddenStopInfo->setFermataLat();
            hiddenStopInfo->setFermataLng();
            hiddenStopInfo->setPositionKnown(false);
        }

    }
}


////////////////////////////////////////////////////////////
// PROPERTIES read/write funcionts
////////////////////////////////////////////////////////////
// PROPERTY MgsBannerStatus READ value
const GTT_StopManager::msgBanner GTT_StopManager::getMgsBannerStatus() { return hiddenMgsBannerStatus; }

// PROPERTY MgsBannerStatus WRITE value
// set status value for grafic banner display
void GTT_StopManager::setMgsBannerStatus(msgBanner value)
{
    if (hiddenMgsBannerStatus != value) {
        hiddenMgsBannerStatus = value;
#if ATTIVADEBUG
        cout << "setloading: " << value << endl;
#endif
        emit GTTon_MgsBannerStatus_changed();
    }

}

// PROPERTY StopPageGUIStatus READ value
const GTT_StopManager::StopPageGUIStatuses GTT_StopManager::getStopPageGUIStatus() { return hiddenStopPageGUIStatus; }
// PROPERTY StopPageGUIStatus WRITE value
void GTT_StopManager::setStopPageGUIStatus(StopPageGUIStatuses status) {
#if ATTIVADEBUG
    cout << "set page status: raggiunto"  << endl;
#endif
    if (hiddenStopPageGUIStatus != status) {
        hiddenStopPageGUIStatus = status;
#if ATTIVADEBUG
        cout << "set page status: " << status << endl;
#endif
        emit GTTon_StopPageGUIStatus_changed();
    }
}


// PROPERTY StopNumber READ value
GTT_Stop* GTT_StopManager::getStopInfo() { return hiddenStopInfo; }

// PROPERTY MultiSelectionStop READ function
const QStringList GTT_StopManager::getMultiSelectionStop() { return hiddenMultiSelectionStop;  }

// PROPERTY SelectMultipleStopsStatus READ function
const GTT_StopManager::SelectMultipleStopsStatuses GTT_StopManager::getSelectMultipleStopsStatus()
{ return hiddenSelectMultipleStopsStatuses; }

// PROPERTY SelectMultipleStopsStatus WRITE function
void GTT_StopManager::setSelectMultipleStopsStatus(SelectMultipleStopsStatuses newStatus)
{
    if (hiddenSelectMultipleStopsStatuses != newStatus) {
        hiddenSelectMultipleStopsStatuses = newStatus;
        emit GTTon_SelectMultipleStopsStatus_changed();
    }
}

////////////////////////////////////////////////////////////
// other functions
////////////////////////////////////////////////////////////

void GTT_StopManager::preferredStopListUpdate()
{
    // simply call the add method if preferred list class
    myPrefStopList->addElement(hiddenStopInfo->getFermataNumero(),
                               hiddenStopInfo->getFermataNome(),
                               hiddenStopInfo->getFermataIndirizzo());

}

int GTT_StopManager::searchByString(QString startNum) {
    //    bool num_ok = false;
    //    int num = startNum.toInt(&num_ok, 10);

    //check if empty
    if(!startNum.trimmed().isEmpty()) {
        GTT_user_new_stop_def(startNum);
    }
}

void GTT_StopManager::removePreferred(QString item) {
    if (myPrefStopList->listSize() > 1)
    {
        //        qDebug() << item;
        bool num_ok = false;
        int nItem = item.toInt(&num_ok, 10);
        //    check if it is the first item of the list. if yes we have to reload the stop
        //    just check if item == 0;
        QMessageBox msgBox;
        //        myPrefStopList->
        //        msgBox.setText("Rimuovere la fermata?");
        //setInformativeText
        msgBox.setText(myPrefStopList->getTitle(item).prepend("Vuoi rimuovere la fermata ").append("?"));
        msgBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
        //    msgBox.setDefaultButton(QMessageBox::Save);
        int ret = msgBox.exec();
        if (ret == QMessageBox::Yes)
        {

            if (num_ok)
                myPrefStopList->removePreferred(nItem);
            if (nItem == 0)
                GTT_user_new_stop_def( myPrefStopList->getFirstPreferred());
        }
    }

}

void GTT_StopManager::reloadStop() {
    // start all the steps as if the users inserted the stop number again.
    // I assume that the first item in the preferred list is the actual loaded element
    GTT_user_new_stop_def( myPrefStopList->getFirstPreferred());

}

int GTT_StopManager::pocketGTTquit() {
    myPrefStopList->savePreferredList2XML();
    QCoreApplication::quit ();
    return 0;
}
